package com.morningstar.system.controller;


import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.morningstar.common.base.BaseController;
import com.morningstar.common.dao.entity.CommonQuery;
import com.morningstar.common.result.Result;
import com.morningstar.common.result.ServiceCheckResult;
import com.morningstar.system.constants.MenuType;
import com.morningstar.system.controller.result.Menu;
import com.morningstar.system.dao.entity.SysMenu;
import com.morningstar.system.service.SysMenuService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

import static com.morningstar.common.constants.permission.PermissionConstants.*;

/**
 * <p>
 * 菜单权限表 前端控制器
 * </p>
 *
 * @author yanglianshan
 * @since 2023-06-28
 */
@Slf4j
@RestController
@RequestMapping("/system/menu")
public class SysMenuController extends BaseController {
    private static final String PERMISSION = "system.menu";
    private static final String PERMISSION_LIST = PERMISSION + LIST;
    private static final String PERMISSION_DETAIL = PERMISSION + DETAIL;
    private static final String PERMISSION_UPDATE = PERMISSION + UPDATE;
    private static final String PERMISSION_ADD = PERMISSION + ADD;
    private static final String PERMISSION_DELETE = PERMISSION + DELETE;

    private static final Long ROOT_MENU_ID = 0L;
    @Resource
    private SysMenuService menuService;


    @SaCheckLogin
    @GetMapping(value = "/tree")
    public Result<Object> list() {
        List<SysMenu> menus = menuService.list()
                .stream()
                .filter(sysMenu -> !StringUtils.equalsIgnoreCase(sysMenu.getMenuType(), MenuType.PERMISSION))
                .toList();
        List<Long> rootIds = new ArrayList<>();
        rootIds.add(ROOT_MENU_ID);
        SysMenu root = new SysMenu();
        root.setMenuId(ROOT_MENU_ID);
        root.setMenuName("根节点");
        root.setMenuType(MenuType.CATALOG);
        root.setChildren(this.buildSysMenuTree(rootIds, menus));
        List<SysMenu> roots = new ArrayList<>();
        roots.add(root);
        return Result.successData(roots);
    }

    @SaCheckLogin
    @GetMapping(value = "/select")
    public Result<Object> select() {
        List<SysMenu> menus = menuService.list();
        return Result.successData(this.buildMenuTree(ROOT_MENU_ID, menus));
    }

    /**
     * 获取用户权限列表
     *
     * @return 获取用户权限
     */
    @SaCheckLogin
    @GetMapping(value = "/userMenu")
    public Result<List<Menu>> userMenu() {
        List<SysMenu> menus = menuService.selectUserMenus(Long.parseLong(StpUtil.getLoginId().toString()))
                .stream()
                .filter(sysMenu -> !StringUtils.equalsIgnoreCase(sysMenu.getMenuType(), MenuType.PERMISSION))
                .toList();
        return Result.successData(this.buildMenuTree(ROOT_MENU_ID, menus));
    }

    @PostMapping(value = "/list")
    @SaCheckPermission(PERMISSION_LIST)
    public Result<List<SysMenu>> list(@RequestBody CommonQuery<SysMenu, SysMenu> commonQuery) {
        SysMenu query = commonQuery.getQuery();
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        if (query != null) {
            queryWrapper.like(StringUtils.isNotBlank(query.getMenuName()), SysMenu::getMenuName, query.getMenuName());
            queryWrapper.like(StringUtils.isNotBlank(query.getRouteName()), SysMenu::getRouteName, query.getRouteName());
            queryWrapper.like(StringUtils.isNotBlank(query.getPerms()), SysMenu::getPerms, query.getPerms());
        }
        List<SysMenu> menus = menuService.list(queryWrapper);
        List<Long> parentIds = menus.stream().map(SysMenu::getParentId).toList();
        List<Long> menuIds = menus.stream().map(SysMenu::getMenuId).toList();
        List<Long> rootIds = parentIds.stream().filter(item -> !menuIds.contains(item)).toList();
        return Result.successData(this.buildSysMenuTree(rootIds, menus));
    }

    @PostMapping
    @SaCheckPermission(PERMISSION_ADD)
    public Result<Object> add(@RequestBody SysMenu sysMenu) {
        ServiceCheckResult checkResult = menuService.checkAddAndUpdate(sysMenu);
        if (checkResult.isResult()) {
           return Result.fail(checkResult.getMessage());
        }
        menuService.save(sysMenu);
        return Result.successNoData();
    }

    @PostMapping(value = "/update")
    @SaCheckPermission(PERMISSION_UPDATE)
    public Result<Object> update(@RequestBody SysMenu sysMenu) {
        ServiceCheckResult checkResult = menuService.checkAddAndUpdate(sysMenu);
        if (checkResult.isResult()) {
            return Result.fail(checkResult.getMessage());
        }
        menuService.updateById(sysMenu);
        return Result.successNoData();
    }

    @GetMapping("/detail")
    @SaCheckPermission(PERMISSION_DETAIL)
    public Result<Object> detail(@RequestParam("menuId") Long menuId) {
        return Result.successData(menuService.getById(menuId));
    }

    @GetMapping("/delete")
    @SaCheckPermission(PERMISSION_DELETE)
    public Result<Object> delete(@RequestParam("menuId") Long menuId) {
        menuService.removeById(menuId);
        return Result.successNoData();
    }

    /**
     * 递归生成菜单
     *
     * @param parentMenuId 根菜单Id
     * @param menus        菜单
     * @return 菜单
     */
    private List<Menu> buildMenuTree(Long parentMenuId, List<SysMenu> menus) {
        List<SysMenu> sysMenus = menus.stream()
                .filter(menu -> Objects.equals(parentMenuId, menu.getParentId()))
                .sorted(Comparator.comparing(SysMenu::getOrderNum))
                .toList();
        List<Menu> result = new ArrayList<>();
        if (CollectionUtil.isEmpty(sysMenus)) {
            return result;
        }
        for (SysMenu sysMenu : sysMenus) {
            Menu menu = Menu.convert(sysMenu);
            menu.setChildren(this.buildMenuTree(sysMenu.getMenuId(), menus));
            result.add(menu);
        }
        return result;
    }

    private List<SysMenu> buildSysMenuTree(List<Long> parentMenuIds, List<SysMenu> menus) {
        List<SysMenu> sysMenus = menus.stream()
                .filter(menu -> parentMenuIds.contains(menu.getParentId()))
                .sorted(Comparator.comparing(SysMenu::getOrderNum))
                .toList();
        List<SysMenu> result = new ArrayList<>();
        if (CollectionUtil.isEmpty(sysMenus)) {
            return null;
        }
        for (SysMenu sysMenu : sysMenus) {
            List<Long> menuIds = new ArrayList<>();
            menuIds.add(sysMenu.getMenuId());
            sysMenu.setChildren(this.buildSysMenuTree(menuIds, menus));
            result.add(sysMenu);
        }
        return result;
    }
}
